//用法：添加如下代码即可 <canvas id="canvas"></canvas>
// 蜂巢动画
export const honeycomb = () => {
  const honeycomb: any = document.getElementById('canvas'),
    ctx = honeycomb.getContext('2d'),
    lines: any[] = [],
    baseRad = (Math.PI * 2) / 6
  let w = (honeycomb.width = window.innerWidth),
    h = (honeycomb.height = window.innerHeight)
  const opts: any = {
    len: 20,
    count: 50,
    baseTime: 10,
    addedTime: 10,
    dieChance: 0.05,
    spawnChance: 1,
    sparkChance: 0.1,
    sparkDist: 10,
    sparkSize: 2,

    color: 'hsl(hue,100%,light%)',
    baseLight: 50,
    addedLight: 10, // [50-10,50+10]
    shadowToTimePropMult: 6,
    baseLightInputMultiplier: 0.01,
    addedLightInputMultiplier: 0.02,

    cx: w / 2,
    cy: h / 2,
    repaintAlpha: 0.04,
    hueChange: 0.1
  }
  let tick = 0,
    dieX = w / 2 / opts.len,
    dieY = h / 2 / opts.len

  ctx.fillStyle = 'black'
  ctx.fillRect(0, 0, w, h)

  function loop() {
    window.requestAnimationFrame(loop)

    ++tick

    ctx.globalCompositeOperation = 'source-over'
    ctx.shadowBlur = 0
    ctx.fillStyle = 'rgba(0,0,0,alp)'.replace('alp', opts.repaintAlpha)
    ctx.fillRect(0, 0, w, h)
    ctx.globalCompositeOperation = 'lighter'

    if (lines.length < opts.count && Math.random() < opts.spawnChance) lines.push(new Line())

    lines.map(function (line) {
      line.step()
    })
  }
  const Line: any = function (this: any) {
    this.reset()
  }
  Line.prototype.reset = function () {
    this.x = 0
    this.y = 0
    this.addedX = 0
    this.addedY = 0

    this.rad = 0

    this.lightInputMultiplier =
      opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random()

    this.color = opts.color.replace('hue', tick * opts.hueChange)
    this.cumulativeTime = 0

    this.beginPhase()
  }
  Line.prototype.beginPhase = function () {
    this.x += this.addedX
    this.y += this.addedY

    this.time = 0
    this.targetTime = (opts.baseTime + opts.addedTime * Math.random()) | 0

    this.rad += baseRad * (Math.random() < 0.5 ? 1 : -1)
    this.addedX = Math.cos(this.rad)
    this.addedY = Math.sin(this.rad)

    if (
      Math.random() < opts.dieChance ||
      this.x > dieX ||
      this.x < -dieX ||
      this.y > dieY ||
      this.y < -dieY
    )
      this.reset()
  }
  Line.prototype.step = function () {
    ++this.time
    ++this.cumulativeTime

    if (this.time >= this.targetTime) this.beginPhase()

    const prop = this.time / this.targetTime,
      wave = Math.sin((prop * Math.PI) / 2),
      x = this.addedX * wave,
      y = this.addedY * wave

    ctx.shadowBlur = prop * opts.shadowToTimePropMult
    ctx.fillStyle = ctx.shadowColor = this.color.replace(
      'light',
      opts.baseLight + opts.addedLight * Math.sin(this.cumulativeTime * this.lightInputMultiplier)
    )
    ctx.fillRect(opts.cx + (this.x + x) * opts.len, opts.cy + (this.y + y) * opts.len, 2, 2)

    if (Math.random() < opts.sparkChance)
      ctx.fillRect(
        opts.cx +
          (this.x + x) * opts.len +
          Math.random() * opts.sparkDist * (Math.random() < 0.5 ? 1 : -1) -
          opts.sparkSize / 2,
        opts.cy +
          (this.y + y) * opts.len +
          Math.random() * opts.sparkDist * (Math.random() < 0.5 ? 1 : -1) -
          opts.sparkSize / 2,
        opts.sparkSize,
        opts.sparkSize
      )
  }
  loop()

  window.addEventListener('resize', function () {
    w = honeycomb.width = window.innerWidth
    h = honeycomb.height = window.innerHeight
    ctx.fillStyle = 'black'
    ctx.fillRect(0, 0, w, h)

    opts.cx = w / 2
    opts.cy = h / 2

    dieX = w / 2 / opts.len
    dieY = h / 2 / opts.len
  })
}
// 银河动画
export const galaxy = () => {
  const canvas: any = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    w = (canvas.width = window.innerWidth),
    h = (canvas.height = window.innerHeight),
    hue = 217,
    stars: any[] = [],
    maxStars = 1400
  let count = 0

  // Cache gradient
  const canvas2 = document.createElement('canvas'),
    ctx2: any = canvas2.getContext('2d')
  canvas2.width = 200
  canvas2.height = 200
  const half = canvas2.width / 2,
    gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half)
  gradient2.addColorStop(0.025, '#fff')
  gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)')
  gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)')
  gradient2.addColorStop(1, 'transparent')

  ctx2.fillStyle = gradient2
  ctx2.beginPath()
  ctx2.arc(half, half, half, 0, Math.PI * 2)
  ctx2.fill()

  // End cache

  function random(min: any, max: any) {
    if (arguments.length < 2) {
      max = min
      min = 0
    }

    if (min > max) {
      const hold = max
      max = min
      min = hold
    }

    return Math.floor(Math.random() * (max - min + 1)) + min
  }

  const Star: any = function (this: any) {
    this.orbitRadius = random(w / 2 - 30, 0)
    this.radius = random(100, this.orbitRadius) / 10
    this.orbitX = w / 2
    this.orbitY = h / 1.4 //顶部高度
    this.timePassed = random(0, maxStars)
    this.speed = random(this.orbitRadius, 100) / 100000
    this.alpha = random(2, 1000) / 10

    count++
    stars[count] = this
  }

  Star.prototype.draw = function () {
    const x = Math.sin(this.timePassed + 1) * this.orbitRadius + this.orbitX,
      y = (Math.cos(this.timePassed) * this.orbitRadius) / 2 + this.orbitY,
      twinkle = random(10, 100)

    if (twinkle === 1 && this.alpha > 0) {
      this.alpha -= 0.05
    } else if (twinkle === 2 && this.alpha < 1) {
      this.alpha += 0.05
    }

    ctx.globalAlpha = this.alpha
    ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius)
    this.timePassed += this.speed
  }

  for (let i = 0; i < maxStars; i++) {
    new Star()
  }

  function animation() {
    ctx.globalCompositeOperation = 'source-over'
    ctx.globalAlpha = 0.8
    ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)'
    ctx.fillRect(0, 0, w, h)

    ctx.globalCompositeOperation = 'lighter'
    for (let i = 1, l = stars.length; i < l; i++) {
      stars[i].draw()
    }

    window.requestAnimationFrame(animation)
  }

  animation()
}
